/*
 * Copyright 2012 Marsrutai.lt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lt.marsrutai.mobile.android.fragment;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import lt.marsrutai.mobile.android.AppContext;
import lt.marsrutai.mobile.android.MarsrutaiLTApp;
import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.activity.PointSelectionMapActivity.MarkerInfo;
import lt.marsrutai.mobile.android.activity.intent.FastestRoutesResultIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.FastestRoutesSearchIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.PointSelectionIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.TaskIntentHolder;
import lt.marsrutai.mobile.android.adapter.NormalizedStringAdapter;
import lt.marsrutai.mobile.android.fragment.task.GetLocationTaskDialogFragment;
import lt.marsrutai.mobile.android.fragment.task.GetStopNamesTaskFragment;
import lt.marsrutai.mobile.android.fragment.task.TaskDialogFragment;
import lt.marsrutai.mobile.android.fragment.task.TaskFragment;
import lt.marsrutai.mobile.android.manager.ActivityManager;
import lt.marsrutai.mobile.android.model.FastestRouteSearchBookmark;
import lt.marsrutai.mobile.android.model.enums.DateTime;
import lt.marsrutai.mobile.android.service.TransportInfoResolver.TransportInfo;
import lt.marsrutai.mobile.android.task.GetLocationTask;
import lt.marsrutai.mobile.android.task.GetStopNamesTask;
import lt.marsrutai.mobile.android.task.GetStopsTask;
import lt.marsrutai.mobile.android.util.PreferenceUtils;
import lt.marsrutai.mobile.android.util.StringUtils;
import lt.marsrutai.mobile.android.widget.AutoCompleteLocationTextView;
import lt.marsrutai.mobile.android.widget.DialogChoiceItem;
import lt.marsrutai.mobile.android.widget.FastestRouteSearchDialogItem;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.DatePicker;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.TimePicker;

import com.actionbarsherlock.app.SherlockFragment;
import com.google.android.gms.maps.model.LatLng;

public class FastestRoutesSearchFragment extends SherlockFragment {

    private static final String TEXT_VIEW_TO_ID = "END";
    private static final String TEXT_VIEW_FROM_ID = "START";

    private static final int POINT_SELECTION_ACTIVITY_REQUEST_CODE = 0;

    private static final String GET_LOCATION_TASK_FRAGMENT_TAG = "getLocationTask";
    private static final String GET_STOP_NAMES_TASK_FRAGMENT_TAG = "getStopNamesTask";

    private static Map<DialogChoiceItem, SelectionHandler> DEFAULT_DIALOG_CHOICES = new LinkedHashMap<DialogChoiceItem, SelectionHandler>();
    static {
        DEFAULT_DIALOG_CHOICES.put(FastestRouteSearchDialogItem.CURRENT_LOCATION.getValue(), null);
        DEFAULT_DIALOG_CHOICES.put(FastestRouteSearchDialogItem.POINT_ON_MAP.getValue(), new SelectionHandler() {

            @Override
            public void handle(Fragment fragment, String ownerId) {
                PointSelectionIntentHolder intentHolder = new PointSelectionIntentHolder(fragment.getActivity());
                List<MarkerInfo> markerInfoList = new ArrayList<MarkerInfo>();

                AutoCompleteLocationTextView textViewFrom = ((FastestRoutesSearchFragment) fragment).textViewFrom;
                boolean fromPointOnMap = textViewFrom.isSelected(FastestRouteSearchDialogItem.POINT_ON_MAP.getValue());
                
                AutoCompleteLocationTextView textViewTo = ((FastestRoutesSearchFragment) fragment).textViewTo;
                boolean toPointOnMap = textViewTo.isSelected(FastestRouteSearchDialogItem.POINT_ON_MAP.getValue());
                
                int pointCount = (fromPointOnMap ? 1 : 0) + (toPointOnMap ? 1 : 0);
                String title = fragment.getActivity().getResources().getQuantityString(R.plurals.fastest_route_point_update_position, pointCount);
                
                if (fromPointOnMap) {
                    markerInfoList.add(createMarker(fragment, textViewFrom, title, TEXT_VIEW_FROM_ID, R.drawable.first_stop));
                }

                if (toPointOnMap) {
                    markerInfoList.add(createMarker(fragment, textViewTo, title, TEXT_VIEW_TO_ID, R.drawable.last_stop));
                }

                intentHolder.setMarkers(markerInfoList);
                fragment.startActivityForResult(intentHolder.getIntent(), POINT_SELECTION_ACTIVITY_REQUEST_CODE);
            }

            protected MarkerInfo createMarker(Fragment fragment, AutoCompleteLocationTextView textView, String title, String viewId, int markerResourceId) {
                Location location = textView.getLocation();
                LatLng latLng = location != null ? new LatLng(location.getLatitude(), location.getLongitude()) : null;
                return new MarkerInfo(viewId, title, null, markerResourceId, latLng, true);
            }
        });
    }
    
    private static Map<Integer, String> CHANGE_COUNT_VALUES = new LinkedHashMap<Integer, String>();
    private static Map<Integer, String> CHANGE_DURATION_VALUES = new LinkedHashMap<Integer, String>();
    private static Map<Integer, String> WALK_DISTANCE_VALUES = new LinkedHashMap<Integer, String>();
    private static Map<Integer, String> WALK_SPEED_VALUES = new LinkedHashMap<Integer, String>();
    static {
        Resources resources = MarsrutaiLTApp.getContext().getResources();
        for (int i : resources.getIntArray(R.array.fastest_route_change_count_values)) {
            CHANGE_COUNT_VALUES.put(i, i == -1 ? resources.getString(R.string.fastest_route_change_count_unlimited) : Integer.toString(i));
        }
        
        for (int i : resources.getIntArray(R.array.fastest_route_walk_speed_values)) {
            WALK_SPEED_VALUES.put(i, resources.getString(R.string.fastest_route_walk_speed_format, i));
        }

        for (int i : resources.getIntArray(R.array.fastest_route_change_duration_values)) {
            CHANGE_DURATION_VALUES.put(i, resources.getString(R.string.fastest_route_change_duration_format, i));
        }

        for (int i : resources.getIntArray(R.array.fastest_route_walk_distance_values)) {
            WALK_DISTANCE_VALUES.put(i, resources.getString(R.string.fastest_route_walk_distance_format, i));
        }
    }

    private FragmentManager fragmentManager;

    private ActivityManager manager;

    private List<String> stopNames;

    private String scopeFolder;
    private Calendar selectedDate;
    private DialogChoiceItem[] dialogChoices;
    private boolean isTimeSetByUser;
    private Integer changeCount;
    private Integer changeDuration;
    private Integer walkDistance;
    private Integer walkSpeed;
    private List<String> transportTypes;

    private Button pickDateButton;
    private Button pickTimeButton;
    private AutoCompleteLocationTextView textViewFrom;
    private AutoCompleteLocationTextView textViewTo;
    private Button searchButton;
    private RadioButton radioDepart;
    private RadioButton radioArrive;

    private Spinner changeCountSpinner;
    private Spinner changeDurationSpinner;
    private Spinner walkDistanceSpinner;
    private Spinner walkSpeedSpinner;

    /**
     * The sole purpose of this map is to assign unique id's to all
     * {@link AutoCompleteLocationTextView}s. These keys are used as request
     * codes for starting a sub activities or as a means to communicate between
     * fragments.
     * 
     * @see {@link #onActivityResult(int, int, Intent)}
     * @see {@link #dialogItemSelected(String, DialogChoiceItem)}
     * @see {@link #isSelected(String, DialogChoiceItem)})
     */
    private Map<String, AutoCompleteLocationTextView> views = new HashMap<String, AutoCompleteLocationTextView>();

    private BroadcastReceiver locationReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            TaskIntentHolder holder = new TaskIntentHolder(intent);

            switch (holder.getStatus()) {
                case Activity.RESULT_OK:
                    Location result = holder.getResult();

                    if (textViewFrom.isSelected(FastestRouteSearchDialogItem.CURRENT_LOCATION.getValue())) {
                        textViewFrom.setLocation(result);
                    }
                    if (textViewTo.isSelected(FastestRouteSearchDialogItem.CURRENT_LOCATION.getValue())) {
                        textViewTo.setLocation(result);
                    }
                    performSearch();
                    break;
                case GetLocationTask.RESULT_LOCATION_NOT_RESOLVED:
                    // Location was not resolved - display errors
                    manager.makeToast(getActivity(), getActivity().getString(holder.getResultMessage()));
                    break;
            }
        }
    };

    private BroadcastReceiver stopNameReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            TaskIntentHolder holder = new TaskIntentHolder(intent);
            stopNames = holder.getStringListResult();

            if (holder.getStatus() == GetStopsTask.RESULT_NOT_RESOLVED) {
                manager.runOnUiThread(manager.errorRes);
            }
            else {
                setStops();
                manager.dismissDownloadLoadingBar();
            }
        }
    };
    
    private BroadcastReceiver timeTickReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (!isTimeSetByUser) {
                setCurrentTime();
                
                updateTimeDisplay();
                updateDateDisplay();
            }
        }
        
    };

    @Override
    public void onResume() {
        super.onResume();

        getActivity().registerReceiver(timeTickReceiver, new IntentFilter(Intent.ACTION_TIME_TICK));
        
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(locationReceiver, new IntentFilter(GetLocationTask.BROADCAST_ACTION));
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(stopNameReceiver, new IntentFilter(GetStopNamesTask.BROADCAST_ACTION));

        if (stopNames == null || stopNames.isEmpty()) {
            // Check whether the worker fragment has been retained
            TaskFragment<?, ?, ?> taskFragment = (TaskFragment<?, ?, ?>) fragmentManager.findFragmentByTag(GET_STOP_NAMES_TASK_FRAGMENT_TAG);
    
            // Start downloading only if we don't have any scopes, and task fragments has not been retained
            if (!TaskFragment.isActive(taskFragment)) {
                downloadData();
            }
        }
        else {
            setStops();
            manager.dismissDownloadLoadingBar();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        
        getActivity().unregisterReceiver(timeTickReceiver);

        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(locationReceiver);
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(stopNameReceiver);
    }

    @Override
    public void onStart() {
        super.onStart();

        // Activity visible - start listening for location updates
        AppContext.getLocationProvider().start();
    }

    @Override
    public void onStop() {
        super.onStart();

        // Activity hidden - stop listening for location updates
        AppContext.getLocationProvider().stop();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        fragmentManager = getFragmentManager();
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        initializeControls();

        views.put(TEXT_VIEW_FROM_ID, textViewFrom);
        views.put(TEXT_VIEW_TO_ID, textViewTo);

        if (manager == null) {
            manager = new ActivityManager(getActivity(), R.string.no_data_fastest_routes_message);
        }

        // Restore state
        restoreState(savedInstanceState);

        setupView();
    }

    protected void initializeControls() {
        textViewFrom = (AutoCompleteLocationTextView) getActivity().findViewById(R.id.point_from);
        textViewTo = (AutoCompleteLocationTextView) getActivity().findViewById(R.id.point_to);
        pickDateButton = (Button) getActivity().findViewById(R.id.entry_date);
        pickTimeButton = (Button) getActivity().findViewById(R.id.entry_time);
        searchButton = (Button) getView().findViewById(R.id.search);
        radioDepart = (RadioButton) getActivity().findViewById(R.id.radio_depart);
        radioDepart.setChecked(true);
        radioArrive = (RadioButton) getActivity().findViewById(R.id.radio_arrive);
        
        changeCountSpinner = (Spinner) getActivity().findViewById(R.id.change_count);
        changeDurationSpinner = (Spinner) getActivity().findViewById(R.id.change_duration);
        walkDistanceSpinner = (Spinner) getActivity().findViewById(R.id.walk_distance);
        walkSpeedSpinner = (Spinner) getActivity().findViewById(R.id.walk_speed);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fastest_route_search, container, false);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        FastestRoutesSearchIntentHolder intentHolder = new FastestRoutesSearchIntentHolder(outState);
        intentHolder.setScopeFolder(scopeFolder);
        intentHolder.setDialogChoices(dialogChoices);
        intentHolder.setIsTimeSetByUser(isTimeSetByUser);

        if (selectedDate != null) {
            intentHolder.setCurrentlySelectedDate(selectedDate.getTimeInMillis());
        }
        intentHolder.setStopNames(stopNames);
        
        intentHolder.setChangeCount(changeCount);
        intentHolder.setChangeDuration(changeDuration);
        intentHolder.setWalkDistance(walkDistance);
        intentHolder.setWalkSpeed(walkSpeed);
        intentHolder.setTransportTypes(transportTypes);

        outState.putAll(intentHolder.getIntent().getExtras());
        super.onSaveInstanceState(outState);
    }

    private void restoreState(Bundle bundle) {
        FastestRoutesSearchIntentHolder intentHolder = new FastestRoutesSearchIntentHolder(bundle != null ? bundle : getArguments());

        scopeFolder = intentHolder.getScopeFolder();
        changeCount = intentHolder.getChangeCount();
        changeDuration = intentHolder.getChangeDuration();
        walkDistance = intentHolder.getWalkDistance();
        walkSpeed = intentHolder.getWalkSpeed();
        transportTypes = intentHolder.getTransportTypes();
        
        if (bundle != null) {
            dialogChoices = intentHolder.getDialogChoices();
            stopNames = intentHolder.getStopNames();
            isTimeSetByUser = intentHolder.getIsTimeSetByUser();
            
            long time = intentHolder.getCurrentlySelectedDate();
            if (time != 0) {
                selectedDate = new DateTime(intentHolder.getCurrentlySelectedDate()).getCalendar();            
            }
        }
        else {
            FastestRouteSearchDialogItem startSelectionType = intentHolder.getStartSelectionType();
            if (startSelectionType != null) {
                textViewFrom.setLocation(intentHolder.getStartLocation());
                
                dialogItemSelectedInternal(TEXT_VIEW_FROM_ID, startSelectionType.getValue(), false);
            }
            else {
                textViewFrom.setText(intentHolder.getStart());
            }
            
            FastestRouteSearchDialogItem endSelectionType = intentHolder.getEndSelectionType();
            if (endSelectionType != null) {
                textViewTo.setLocation(intentHolder.getEndLocation());
                
                dialogItemSelectedInternal(TEXT_VIEW_TO_ID, endSelectionType.getValue(), false);
            }
            else {
                textViewTo.setText(intentHolder.getEnd());
            }

            boolean isArrivalInd = intentHolder.getIsArrivalInd();
            radioDepart.setChecked(!isArrivalInd);
            radioArrive.setChecked(isArrivalInd);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == POINT_SELECTION_ACTIVITY_REQUEST_CODE) {
            PointSelectionIntentHolder intentHolder = new PointSelectionIntentHolder(data);

            if (resultCode == Activity.RESULT_OK) {
                List<MarkerInfo> markers = intentHolder.getMarkers();

                for (MarkerInfo markerInfo : markers) {
                    AutoCompleteLocationTextView view = views.get(markerInfo.getId());
                    if (view != null) {
                        Location location = new Location((String) null);
                        location.setLatitude(markerInfo.getLatLng().latitude);
                        location.setLongitude(markerInfo.getLatLng().longitude);
                        view.setLocation(location);
                    }
                }
            }
            else {
                // clear view text, if a dialog item was selected and the view has no location set (except for current location selection)
                for (AutoCompleteLocationTextView view : views.values()) {
                    if (view.getLocation() == null && view.getSelectedChoice() != null && !view.isSelected(FastestRouteSearchDialogItem.CURRENT_LOCATION.getValue())) {
                        view.removeSelectedChoice();
                    }
                }
            }
        }
    }

    public void downloadData() {
        TaskFragment.download(fragmentManager, 
                GetStopNamesTaskFragment.class, GET_STOP_NAMES_TASK_FRAGMENT_TAG, 
                scopeFolder);
    }

    public void setupView() {
        if (getActivity() == null) {
            // Original activity was killed while the data was downloading - a
            // new one will take it's place and setup the view
            return;
        }

        setDateTime();
        setSearchButton();
        setupAdvancedSearchControls();

        if (dialogChoices == null) {
            List<DialogChoiceItem> items = new ArrayList<DialogChoiceItem>();
            for (DialogChoiceItem defaultItem : DEFAULT_DIALOG_CHOICES.keySet()) {
                items.add(defaultItem.clone());
            }
            dialogChoices = items.toArray(new DialogChoiceItem[DEFAULT_DIALOG_CHOICES.size()]);
        }

        Button startPointDialog = (Button) getActivity().findViewById(R.id.point_from_dialog);
        startPointDialog.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                DialogFragment dialog = new PointSelectionDialogFragment();
                FastestRoutesSearchIntentHolder holder = new FastestRoutesSearchIntentHolder(getActivity());
                holder.setDialogTitle(getString(R.string.fastest_route_choose_start_point_title));
                holder.setDialogChoices(dialogChoices);
                holder.setDialogOwnerId(TEXT_VIEW_FROM_ID);

                dialog.setArguments(holder.getIntent().getExtras());
                dialog.show(getActivity().getSupportFragmentManager(), "StartPointSelectionDialogFragment");
            }
        });
        Button finishPointDialog = (Button) getActivity().findViewById(R.id.point_to_dialog);
        finishPointDialog.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                DialogFragment dialog = new PointSelectionDialogFragment();
                FastestRoutesSearchIntentHolder holder = new FastestRoutesSearchIntentHolder(getActivity());
                holder.setDialogTitle(getString(R.string.fastest_route_choose_end_point_title));
                holder.setDialogChoices(dialogChoices);
                holder.setDialogOwnerId(TEXT_VIEW_TO_ID);

                dialog.setArguments(holder.getIntent().getExtras());
                dialog.show(getActivity().getSupportFragmentManager(), "FinishPointSelectionDialogFragment");
            }
        });
    }

    private void setSearchButton() {
        searchButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                sendItemData();
            }
        });
    }
    
    /**
     * Sets up advanced search controls
     */
    private void setupAdvancedSearchControls() {
        setupSpinner(changeCountSpinner, CHANGE_COUNT_VALUES, changeCount, PreferenceUtils.FASTEST_ROUTE_CHANGE_COUNT);
        setupSpinner(changeDurationSpinner, CHANGE_DURATION_VALUES, changeDuration, PreferenceUtils.FASTEST_ROUTE_CHANGE_DURATION);
        setupSpinner(walkDistanceSpinner, WALK_DISTANCE_VALUES, walkDistance, PreferenceUtils.FASTEST_ROUTE_WALK_DISTANCE);
        setupSpinner(walkSpeedSpinner, WALK_SPEED_VALUES, walkSpeed, PreferenceUtils.FASTEST_ROUTE_WALK_SPEED);

        Map<String, Boolean> selectedTransportTypes = new HashMap<String, Boolean>();
        boolean checkByDefault = true;
        if (transportTypes == null) {
            selectedTransportTypes.putAll(PreferenceUtils.<String, Boolean>getSerializedPreferenceMap(getActivity(), PreferenceUtils.FASTEST_ROUTE_TRANSPORT_TYPES));
        }
        else {
            checkByDefault = false;
            for (String transportType : transportTypes) {
                selectedTransportTypes.put(getTransportTypePreferenceKey(transportType), Boolean.TRUE);
            }
        }
        LinearLayout transportTypeContainer = (LinearLayout) getActivity().findViewById(R.id.transport_type_container);
        
        Set<TransportInfo> scopeTransports = new TreeSet<TransportInfo>(TransportInfo.INDEX_COMPARATOR);
        scopeTransports.addAll(AppContext.getTransportInfoResolver().getTransportInfo(scopeFolder));
        
        for (TransportInfo transportInfo : scopeTransports) {
            Boolean selectionPreference = selectedTransportTypes == null ? null : selectedTransportTypes.get(getTransportTypePreferenceKey(transportInfo.getTransportId()));
            boolean isTransportTypeChecked = false;
            
            if (selectionPreference == null) {
                // Transport types are shown as selected by default
                isTransportTypeChecked = checkByDefault;
            } else {
                isTransportTypeChecked = selectionPreference;
            }
            
            CheckBox checkBox = new CheckBox(getActivity());
            checkBox.setText(transportInfo.getLocalizedNamePlural());
            checkBox.setChecked(isTransportTypeChecked);
            checkBox.setTag(transportInfo);
            checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    TransportInfo transportInfo = (TransportInfo) buttonView.getTag();
                    if (transportTypes == null) {
                        PreferenceUtils.addSerializedMapPreferenceValue(getActivity(), PreferenceUtils.FASTEST_ROUTE_TRANSPORT_TYPES,
                                getTransportTypePreferenceKey(transportInfo.getTransportId()), isChecked);
                    }
                    else {
                        // if transport types are from set via intent, manage the list manually
                        if (isChecked) {
                            transportTypes.add(transportInfo.getTransportId());
                        }
                        else {
                            transportTypes.remove(transportInfo.getTransportId());
                        }
                    }
                }
            });
            transportTypeContainer.addView(checkBox);
        }

        final View settings = (View) getActivity().findViewById(R.id.settings);
        final ImageView settingsToggleImage = (ImageView) getActivity().findViewById(R.id.settings_toggle_image);
        View settingsToggle = (View) getActivity().findViewById(R.id.settings_toggle);
        settingsToggle.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                if (settings.getVisibility() == View.GONE) {
                    settings.setVisibility(View.VISIBLE);
                    settingsToggleImage.setImageResource(R.drawable.arrow_up);
                }
                else {
                    settings.setVisibility(View.GONE);
                    settingsToggleImage.setImageResource(R.drawable.arrow_down);
                }
            }
        });
    }

    protected String getTransportTypePreferenceKey(String transprotInfoId) {
        return scopeFolder + "-" + transprotInfoId;
    }

    /**
     * Sets up a spinner which uses values from a valueMap.
     * 
     * @param spinnerId
     * @param valueMap {value -> label} map
     * @param preferenceKey Preference key to load/store selection
     */
    protected void setupSpinner(Spinner spinner, final Map<Integer, String> valueMap, final Integer value, final String preferenceKey) {
        SpinnerAdapter adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_dropdown_item, new ArrayList<String>(valueMap.values()));
        spinner.setAdapter(adapter);
        spinner.setSelection(value != null ? getSpinnerValuePosition(valueMap, value) : getSpinnerSelectionPreferencePosition(valueMap, preferenceKey));
        spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
                if (value == null) {
                    saveSpinnerSelectionPreference(valueMap, preferenceKey, pos);
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
    }

    /**
     * Gets the position of the initial spinner selection
     * 
     * @param valueMap
     * @param preferenceKey
     * @return
     */
    private int getSpinnerSelectionPreferencePosition(Map<Integer, String> valueMap, String preferenceKey) {
        int value = (Integer) PreferenceUtils.getPreferenceValue(getActivity(), preferenceKey);
        
        return getSpinnerValuePosition(valueMap, value);
    }

    protected int getSpinnerValuePosition(Map<Integer, String> valueMap, int value) {
        return new ArrayList<Integer>(valueMap.keySet()).indexOf(value);
    }

    /**
     * Saves spinner selection
     * 
     * @param valueMap
     * @param preferenceKey
     * @param pos
     */
    private void saveSpinnerSelectionPreference(Map<Integer, String> valueMap, String preferenceKey, int pos) {
        int value = valueMap.keySet().toArray(new Integer[valueMap.size()])[pos];
        PreferenceUtils.setIntegerPreferenceValue(getActivity(), preferenceKey, value);
    }

    protected Integer getSpinnerSelectionValue(Map<Integer, String> valueMap, Spinner spinner) {
        return new ArrayList<Integer>(valueMap.keySet()).get(spinner.getSelectedItemPosition());
    }

    private void sendItemData() {
        String start = textViewFrom.getText().toString();
        String finish = textViewTo.getText().toString();

        if (StringUtils.isEmpty(start)) {
            manager.makeToast(getActivity(), getString(R.string.no_start_point));
            return;
        }

        if (StringUtils.isEmpty(finish)) {
            manager.makeToast(getActivity(), getString(R.string.no_finish_point));
            return;
        }

        /*
         * If any of the selections were "current location", then proceed to acquire current location
         * and invoke search when finished.
         */
        if (textViewFrom.isSelected(FastestRouteSearchDialogItem.CURRENT_LOCATION.getValue()) || textViewTo.isSelected(FastestRouteSearchDialogItem.CURRENT_LOCATION.getValue())) {
            // Create a task fragment which will keep an eye on GetLocationTask
            TaskDialogFragment.download(fragmentManager, 
                    GetLocationTaskDialogFragment.class, GET_LOCATION_TASK_FRAGMENT_TAG);

            return;
        }

        // Normal flow - "current location was not selected"
        performSearch();
    }

    protected void performSearch() {
        Location locationFrom = textViewFrom.getLocation();
        Location locationTo = textViewTo.getLocation();
        String start = locationFrom != null ? formatLocation(locationFrom) : textViewFrom.getText().toString();
        String finish = locationTo != null ? formatLocation(locationTo) : textViewTo.getText().toString();

        FastestRoutesResultIntentHolder intentHolder = new FastestRoutesResultIntentHolder(getActivity());
        intentHolder.setScopeFolder(scopeFolder);
        intentHolder.setStopFrom(start);
        intentHolder.setStopTo(finish);
        intentHolder.setDateTime(pickDateButton.getText() + "T" + pickTimeButton.getText());
        intentHolder.setIsArrivalInd(getIsArrivalInd());
        intentHolder.setMaxRides(getSpinnerSelectionValue(CHANGE_COUNT_VALUES, changeCountSpinner) + 1);// change count = rides + 1
        intentHolder.setChangeDuration(getSpinnerSelectionValue(CHANGE_DURATION_VALUES, changeDurationSpinner));
        intentHolder.setMaxWalkDistance(getSpinnerSelectionValue(WALK_DISTANCE_VALUES, walkDistanceSpinner));
        intentHolder.setWalkSpeed(getSpinnerSelectionValue(WALK_SPEED_VALUES, walkSpeedSpinner));
        intentHolder.setBookmarkRepresentation(getBookmarkRepresentation());
        
        List<String> transports = getTransportTypes();
        intentHolder.setTransports(StringUtils.join(transports, ","));
        
        startActivity(intentHolder.getIntent());
    }

    protected List<String> getTransportTypes() {
        LinearLayout transportTypeContainer = (LinearLayout) getActivity().findViewById(R.id.transport_type_container);
        List<String> transports = new ArrayList<String>();
        for (int i = 0; i < transportTypeContainer.getChildCount(); i++) {
            CheckBox checkBox = (CheckBox) transportTypeContainer.getChildAt(i);
            TransportInfo transportInfo = (TransportInfo) checkBox.getTag();
            if (checkBox.isChecked()) {
                transports.add(transportInfo.getTransportId());
            }
        }
        return transports;
    }

    protected boolean getIsArrivalInd() {
        return radioArrive.isChecked();
    }

    private String formatLocation(Location location) {
        return String.format(Locale.US, "@%.8f;%.8f", location.getLatitude(), location.getLongitude());
    }

    private void setStops() {
        NormalizedStringAdapter<String> stop_from = new NormalizedStringAdapter<String>(getActivity(),
                android.R.layout.simple_dropdown_item_1line, stopNames);
        textViewFrom.setThreshold(2);
        textViewFrom.setAdapter(stop_from);
        textViewFrom.setOnEditorActionListener(new OnEditorActionListener() {

            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
                    textViewTo.requestFocus();
                    // Must return true here to consume event
                    return true;
                }
                return false;
            }
        });

        NormalizedStringAdapter<String> stop_to = new NormalizedStringAdapter<String>(getActivity(),
                android.R.layout.simple_dropdown_item_1line, stopNames);
        textViewTo.setThreshold(2);
        textViewTo.setAdapter(stop_to);
        textViewTo.setOnEditorActionListener(new OnEditorActionListener() {

            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {
                    sendItemData();
                    // Must return true here to consume event
                    return true;
                }
                return false;
            }
        });
    }

    private void setDateTime() {
        if (selectedDate == null) {
            setCurrentTime();
        }

        pickDateButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                DialogFragment dialog = new DatePickerFragment();

                FastestRoutesSearchIntentHolder holder = new FastestRoutesSearchIntentHolder(getActivity());
                holder.setCurrentlySelectedDate(selectedDate.getTimeInMillis());
                dialog.setArguments(holder.getIntent().getExtras());

                dialog.show(getActivity().getSupportFragmentManager(), "datePicker");
            }
        });
        pickTimeButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                DialogFragment dialog = new TimePickerFragment();

                FastestRoutesSearchIntentHolder holder = new FastestRoutesSearchIntentHolder(getActivity());
                holder.setCurrentlySelectedDate(selectedDate.getTimeInMillis());
                dialog.setArguments(holder.getIntent().getExtras());

                dialog.show(getActivity().getSupportFragmentManager(), "timePicker");
            }
        });
        updateTimeDisplay();
        updateDateDisplay();
    }

    protected void setCurrentTime() {
        DateTime dateTime = new DateTime();
        selectedDate = dateTime.getCalendar();
    }

    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        selectedDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
        selectedDate.set(Calendar.MINUTE, minute);
        isTimeSetByUser = true;
        
        updateTimeDisplay();
    }

    public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        selectedDate.set(Calendar.YEAR, year);
        selectedDate.set(Calendar.MONTH, monthOfYear);
        selectedDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        isTimeSetByUser = true;
        
        updateDateDisplay();
    }

    private void updateTimeDisplay() {
        pickTimeButton.setText(new StringBuilder().append(pad(selectedDate.get(Calendar.HOUR_OF_DAY))).append(":")
                .append(pad(selectedDate.get(Calendar.MINUTE))));
    }

    private void updateDateDisplay() {
        pickDateButton.setText(new StringBuilder().append(selectedDate.get(Calendar.YEAR)).append("-")
                .append(pad(selectedDate.get(Calendar.MONTH) + 1)).append("-").append(pad(selectedDate.get(Calendar.DAY_OF_MONTH))));
    }
    
    private static String pad(int c) {
        if (c >= 10) {
            return String.valueOf(c);
        }
        else {
            return "0" + String.valueOf(c);
        }
    }

    /**
     * Callback from location selection dialog
     *
     * @param id
     * @param ownerId
     *            Owner view id
     */
    public void dialogItemSelected(String ownerId, DialogChoiceItem item) {
        dialogItemSelectedInternal(ownerId, item, true);
    }

    private void dialogItemSelectedInternal(String ownerId, DialogChoiceItem item, boolean handle) {
        views.get(ownerId).setSelectedChoice(item);
        
        SelectionHandler handler = DEFAULT_DIALOG_CHOICES.get(item);
        if (handler != null && handle) {
            handler.handle(this, ownerId);
        }
    }

    /**
     * Callback from location selection dialog.
     * Delegates call to {@link AutoCompleteLocationTextView#isSelected(DialogChoiceItem)}
     *
     * @param ownerId
     * @param item
     * @return
     */
    public boolean isSelected(String ownerId, DialogChoiceItem item) {
        return views.get(ownerId).isSelected(item);
    }
    
    /**
     * Handles {@link DialogChoiceItem} selection events
     *
     * @author Justas
     */
    private interface SelectionHandler {

        void handle(Fragment fragment, String ownerId);
    }

    public FastestRouteSearchBookmark getBookmarkRepresentation() {
        FastestRouteSearchBookmark bookmark = new FastestRouteSearchBookmark();
        
        bookmark.setScopeFolder(scopeFolder);
        
        bookmark.setStart(textViewFrom.getText().toString());
        Location startLocation = textViewFrom.getLocation();
        bookmark.setStartLat(startLocation == null ? null : startLocation.getLatitude());
        bookmark.setStartLng(startLocation == null ? null : startLocation.getLongitude());
        bookmark.setStartSelectionType(FastestRouteSearchDialogItem.valueOf(textViewFrom.getSelectedChoice()));
        
        bookmark.setEnd(textViewTo.getText().toString());
        Location endLocation = textViewTo.getLocation();
        bookmark.setEndLat(endLocation == null ? null : endLocation.getLatitude());
        bookmark.setEndLng(endLocation == null ? null : endLocation.getLongitude());
        bookmark.setEndSelectionType(FastestRouteSearchDialogItem.valueOf(textViewTo.getSelectedChoice()));
        
        bookmark.setIsArrivalInd(getIsArrivalInd());

        bookmark.setChangeCount(getSpinnerSelectionValue(CHANGE_COUNT_VALUES, changeCountSpinner));
        bookmark.setChangeDuration(getSpinnerSelectionValue(CHANGE_DURATION_VALUES, changeDurationSpinner));
        bookmark.setWalkDistance(getSpinnerSelectionValue(WALK_DISTANCE_VALUES, walkDistanceSpinner));
        bookmark.setWalkSpeed(getSpinnerSelectionValue(WALK_SPEED_VALUES, walkSpeedSpinner));
        bookmark.setTransportTypes(getTransportTypes());
        
        return bookmark;
    }
}
